//#include <vector> 
#include <string> 
#include <fstream> 
#include <strstream> 
#include <iostream> 
 
using namespace std; 


// defining data types 
typedef double         DOUBLE; 
typedef double         REAL;
typedef unsigned char  UCHAR; 
typedef char           CHAR; 
typedef unsigned long  UINT; 
typedef long           INT; 
typedef unsigned short USHORT; 
typedef short          SHORT; 
typedef void           VOID; 

#ifndef _MAX_PATH 
#define _MAX_PATH 255 
#endif 

#ifndef _MAX_LEN
#define _MAX_LEN 120
#endif

#ifndef FALSE 
#define FALSE 0 
#endif 
 
#ifndef TRUE 
#define TRUE 1 
#endif 

#define MIN(x,y) ((x)>(y)?(y):(x))
#define MAX(x,y) ((x)<(y)?(y):(x))
#ifdef WIN32
  #define RAND(x)  ((int) ((x)*(rand()/RAND_MAX)))
  #define SRAND(x) srand(x)
#else
  #define RAND(x)  ((int) (drand48()*(x)))
  #define SRAND(x) (srand48(x))
#endif

CHAR              inFile[_MAX_PATH];
CHAR              outFile[_MAX_PATH];
CHAR              kmFile[_MAX_PATH];
INT               numClasses, conversionType, numExamples, numClusters, new_numExamples, dim1, dim2;
INT *class_occurrence;
INT * membership;
INT *belonging;
REAL **point;
REAL **new_point;
REAL **center;
INT *target;
INT *new_target;
INT *centerTarget;

// ------------------------------------------------------
INT checkLineArg(INT argn, CHAR** argv){ 
 
  INT i;
  numClasses=2;
  conversionType=3;

  for(i = 1 ; i < argn; i++){ 
   if(strcmp(argv[i],"-i")==0){ 
      strcpy(inFile,argv[++i]); 
    } 
    else if(strcmp(argv[i],"-o")==0){ 
      strcpy(outFile,argv[++i]); 
    } 
    else if(strcmp(argv[i],"-km")==0){ 
      strcpy(kmFile,argv[++i]); 
    } 
    else if(strcmp(argv[i],"-c")==0){
      numClasses = atoi(argv[++i]); 
    } 	 
    else if(strcmp(argv[i],"-t")==0){
      conversionType = atoi(argv[++i]); 
    } 	 
    else if(strcmp(argv[i],"-h")==0){
      return FALSE;
    }

  }
 
  return TRUE; 
} 
// ------------------------------------------------------
INT readInputData(){

  INT i, j;
  ifstream file(inFile);
  REAL tmp;

  if (!file) {
    cerr << "Error when opening " << inFile << endl;
    return FALSE;
  }

  cout << "Reading SMOBR file..." << endl;
  file >> numExamples;
  file >> dim1;

  /*
  for (i = 0; i < numExamples; i++) {
    vector<REAL_NUMBER> vtmp;
    for (j = 0; j < dim1; j++) {
      file >> tmp;
      vtmp.push_back(tmp);
    }
    point.push_back(vtmp);
    file >> tmp;
    target.push_back(tmp);
    if(((i+1)%(numExamples/10))==0)
      cout << "." << flush;
  }
  */
  
  try{ 
    point=new REAL *[numExamples];
    target=new INT[numExamples];
	for (i=0;i<numExamples;i++)
      point[i]=new REAL[dim1];
  }
  catch(...){
  cerr<<"Error allocating memory: readInputData()"<<endl;
  exit(1);
  }

  for (i = 0; i < numExamples; i++) {
    for (j = 0; j < dim1; j++) {
      file >> tmp;
      point[i][j]=tmp;
    }
    file >> tmp;
    target[i]=(int)tmp;
  }
	
  cout << endl;
  file.close();
  return TRUE;
}
// ------------------------------------------------------
INT readKmeansData(){

  INT version_kmeans, i, j;
  REAL time_kmeans;
  ifstream file(kmFile);
  REAL tmp;
  CHAR str[_MAX_LEN];

  if (!file) {
    cerr << "Error when opening " << kmFile << endl;
    return FALSE;
  }

  cout << "Reading KMEANS output file..." << endl;
  
  file.getline(str,_MAX_LEN,'\n');//not used
 
  file.getline(str,_MAX_LEN,'\n');
  version_kmeans = atoi(str);

  file.getline(str,_MAX_LEN,'\n');//not used
  
  file.getline(str,_MAX_LEN,'\n');
  time_kmeans = atof(str);

  file.getline(str,_MAX_LEN,'\n');//not used
  
  file.getline(str,_MAX_LEN,'\n');
  numClusters = atoi(str);

  file.getline(str,_MAX_LEN,'\n');//not used
  
  file.getline(str,_MAX_LEN,'\n');
  dim2 = atoi(str);
  
  file.getline(str,_MAX_LEN,'\n');//not used
   
  try{ 
	center=new REAL *[numClusters];
    membership=new INT[numExamples];
	for (i=0;i<numClusters;i++)
	  center[i]=new REAL[dim2];
  }
  catch(...){
  cerr<<"Error allocating memory: readKmeansData()"<<endl;
  exit(1);
  }
 
  for (i = 0; i < numClusters; i++) {
    for (j = 0; j < dim2-1; j++) {
      file.getline(str,_MAX_LEN,' ');
	  tmp=atof(str);
      center[i][j]=tmp;
    }
    file.getline(str,_MAX_LEN,'\n');
    tmp=atof(str);
    center[i][dim2-1]=tmp;
  }

/*
  for (i = 0; i < numClusters; i++) {
    vector<REAL_NUMBER> vtmp;
    for (j = 0; j < dim2; j++) {
      file >> tmp;
      vtmp.push_back(tmp);
    }
    center.push_back(vtmp);
    if(((i+1)%(numClusters/10))==0)
      cout << "." << flush;
    }
*/

  file.getline(str,_MAX_LEN,'\n');//not used

  for (i = 0; i < numExamples; i++) {
    file.getline(str,_MAX_LEN,'\n');
	tmp=atof(str);
    membership[i]=(int)tmp;
  }
  cout << endl;
  file.close();
  return TRUE;
}
// ------------------------------------------------------
INT isSameClass(int a){
INT j, i=0;
while (membership[i]!=a)
  i++;
centerTarget[a]=target[i];
i++;
for (j=i; j<numExamples; j++)
  if (membership[j]==a)
    if (target[j]!=centerTarget[a])
      return FALSE;

return TRUE;
}
//-------------------------------------------------------
INT findCenterClass(int a){
INT i;
INT pos=0;
INT neg=0;
if (numClasses){
  for (i=0; i<numExamples; i++){
    if (membership[i]==a)
      class_occurrence[target[i]]++;
  }
  centerTarget[a]=0;
  for (i=1; i<numClasses; i++)
    centerTarget[a]=(class_occurrence[i]>class_occurrence[centerTarget[a]]?i:centerTarget[a]);
}
else{
  SRAND(time(NULL));
  centerTarget[a]=RAND(1);
  centerTarget[a]=(!centerTarget[a]?-1:1);
  for (i=0; i<numExamples; i++){
    if (membership[i]==a){
	  if(target[i]<0)
        neg++;
      else
		pos++;
	}
  }
  /*if (class_occurrence[0]>class_occurrence[1])
    centerTarget[a]=-1;
  if (class_occurrence[1]>class_occurrence[0])
    centerTarget[a]=1;
  */
  if (neg>pos)
	  centerTarget[a]=-1;
  if (pos>neg)
	  centerTarget[a]=1;
}

return TRUE;
}
//-------------------------------------------------------
INT joinCenter(int a){
  belonging[numExamples+a]++;
  return TRUE;
}
//-------------------------------------------------------
INT joinVectors(int a){
  INT i;
  for (i=0; i<numExamples;i++)
    if (membership[i]==a)
  	  belonging[i]++;
  return TRUE;
}
//-------------------------------------------------------
INT initVectors(){
INT i;

try{
  centerTarget=new INT[numClusters];
  belonging=new INT[numExamples+numClusters];
  class_occurrence=new INT[numClasses];
}
catch(...){
cerr<<"Error allocating memory: initVectors()"<<endl;
exit(1);
}

for (i=0; i<numClusters; i++)
  centerTarget[i]=-2;

for (i=0; i<numExamples+numClusters; i++)
  belonging[i]=0;

for (i=0; i<numClasses; i++)
  class_occurrence=0;

for (i=0; i<numExamples; i++)
  if (target[i]<0){
    numClasses=0;
    break;
  }
return TRUE;
}
//-------------------------------------------------------
INT printHelp(){
  cout << "This will be the help soon..."<<endl;
  return TRUE;
}
//-------------------------------------------------------
INT printSummary(){
cout << "######## Summary of kmeans conversion ########" << endl;
cout << "----------------------------------------------" << endl;
cout << "# Dimension:                            " << dim1 << endl;
cout << "# Conversion type:                      ";
if (conversionType==1)
  cout << "HARD" << endl;
if (conversionType==2)
  cout << "SOFT" << endl;
if (conversionType==3)
  cout << "COMPLETE" << endl;
if (conversionType==4)
  cout << "HARD-MARGIN" << endl;
if (conversionType==5)
  cout << "SOFT-MARGIN" << endl;
cout << "# Number of original data examples:     " << numExamples << endl;
cout << "# Number of clusters created by kmeans: " << numClusters << endl;
cout << "# Number of new data examples:          " << new_numExamples << endl;
if (numClasses) 
  cout << "# Number of classes:                    " << numClasses << endl;
else
  cout << "# Number of classes:                    2 (-1/+1)" << endl;

return TRUE;
}
//-------------------------------------------------------
INT saveResult(){

INT i, j, x;
ofstream file(outFile);

if(!file){
  cout << "Error opening " << outFile << endl;
  exit(1);
}

INT newPointSize=0;
//for (i=0;i<numExamples+numClusters;i++)
//  if (belonging[i])
//    newPointSize++;
newPointSize=numExamples+numClusters;

try{new_point=new REAL *[newPointSize];
    new_target=new INT[newPointSize];
	for (i=0;i<newPointSize;i++)
      new_point[i]=new REAL[dim1];
}
catch(...){
cerr<<"Error allocating memory: saveResult()"<<endl;
exit(1);
}


x=0;
for (i=0; i<numExamples; i++)
  if (belonging[i]){
    for(j=0;j<dim1;j++)
	  new_point[x][j]=point[i][j];
    new_target[x]=target[i];
    x++;
  }
for (i=numExamples; i<numExamples+numClusters; i++)
  if (belonging[i]){
    for (j=0;j<dim2;j++)
	  new_point[x][j]=center[i-numExamples][j];
    new_target[x]=centerTarget[i-numExamples];
    x++;
  }
new_numExamples=x;

/*
for(i=0;i<numClusters+numExamples;i++)
  cout<<belonging[i]<<endl;


for(i=0;i<numExamples;i++)
  cout<<target[i]<<endl;


for(i=0;i<numExamples;i++)
  cout<<membership[i]<<endl;
*/

file << new_numExamples << endl;
file << dim1 << endl;
for(i = 0 ; i < new_numExamples ; i++){
  for(j = 0 ; j < dim1 ; j++)
    file << new_point[i][j] << " ";
  file << new_target[i] << " " << endl;
}
file.close();
return TRUE;
}
//-------------------------------------------------------
INT deleteAll(){
INT i;
delete class_occurrence;
delete membership;
delete belonging;
delete target;
delete centerTarget;
delete new_target;
for (i=0;i<numExamples;i++)
  delete point[i];
for (i=0;i<numClusters;i++)
  delete center[i];
for (i=0;i<new_numExamples;i++)
  delete new_point[i];
delete point;
delete center;
delete new_point;
return TRUE;
}
//-------------------------------------------------------
INT main(INT argn, CHAR** argv){

  UINT i;
  
  if (!checkLineArg(argn,argv))
    return printHelp();

  if (!readInputData()){
    cerr << "Error in readInputData" << endl;
    return FALSE;
  }
  if (!readKmeansData()){
    cerr << "Error in readKmeansData" << endl;
    return FALSE;
  }

  if (dim1!=dim2){
    cerr << "Dimension read from kmeans file: " << dim2 << endl << "Dimension read from input data file: " << dim1 << endl; 
    return FALSE;
  }

  initVectors();

  switch(conversionType){
  case 1: 
    for (i=0; i<numClusters; i++){
      if (isSameClass(i))
        joinCenter(i);
    }
    break;
  case 2:
    for (i=0; i<numClusters; i++){
      if (isSameClass(i))
        joinCenter(i);
      else {
       findCenterClass(i);
       joinCenter(i);
      }
    }
    break;
  case 3:
    for (i=0; i<numClusters; i++){
      if (isSameClass(i))
        joinCenter(i);
      else 
		joinVectors(i);
    }
    break;
  case 4:
    for (i=0; i<numClusters; i++){
  	  if (!isSameClass(i)){
        findCenterClass(i);
        joinCenter(i);
	  }
    }
	break;
  case 5:
    for (i=0; i<numClusters; i++)
      if (!isSameClass(i))
        joinVectors(i);
    break;
  case 6:
    break;
  }

  saveResult();
  printSummary();
  deleteAll();
  return TRUE;
}











